home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / find.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  15.7 KB  |  660 lines

  1. /* Find file command for the Midnight Commander
  2.    Copyright (C) The Free Software Foundation
  3.    Written 1995 by Miguel de Icaza
  4.  
  5.    Complete rewrote.
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include <config.h>
  22. #include "tty.h"
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <malloc.h>    /* For free() */
  26. #include <sys/types.h>
  27. #ifdef HAVE_UNISTD_H
  28. #   include <unistd.h>
  29. #endif
  30.  
  31. /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
  32. #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
  33. #   include <dirent.h>
  34. #   define NLENGTH(dirent) (strlen ((dirent)->d_name))
  35. #else
  36. #   define dirent direct
  37. #   define NLENGTH(dirent) ((dirent)->d_namlen)
  38.  
  39. #   ifdef HAVE_SYS_NDIR_H
  40. #       include <sys/ndir.h>
  41. #   endif /* HAVE_SYS_NDIR_H */
  42.  
  43. #   ifdef HAVE_SYS_DIR_H
  44. #       include <sys/dir.h>
  45. #   endif /* HAVE_SYS_DIR_H */
  46.  
  47. #   ifdef HAVE_NDIR_H
  48. #       include <ndir.h>
  49. #   endif /* HAVE_NDIR_H */
  50. #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
  51.  
  52. #include <sys/stat.h>
  53. #include <sys/param.h>
  54. #include "global.h"
  55. #include "mad.h"
  56. #include "util.h"
  57. #include "win.h"
  58. #include "color.h"
  59. #include "global.h"
  60.  
  61. extern int verbose;        /* Should be in a more sensible header file */
  62.  
  63. /* Dialog manager and widgets */
  64. #include "dlg.h"
  65. #include "widget.h"
  66.  
  67. #include "dialog.h"     /* For do_refresh() */
  68. #define  DIR_H_INCLUDE_HANDLE_DIRENT
  69. #include "dir.h"
  70. #include "panel.h"        /* current_panel */
  71. #include "main.h"        /* do_cd, try_to_select */
  72. #include "wtools.h"
  73. #include "tree.h"
  74. #include "../vfs/vfs.h"
  75.  
  76. #ifdef HAVE_XVIEW
  77. #include "xvmain.h"
  78. #endif
  79.  
  80.  
  81. /* Size of the find parameters window */
  82. #define FIND_Y 10
  83. #define FIND_X 50
  84.  
  85. /* Size of the find window */
  86. #define FIND2_Y 20
  87. #define FIND2_X 50
  88.  
  89. /* A couple of extra messages we need */
  90. #define B_STOP   B_USER+1
  91. #define B_AGAIN  B_USER+2
  92. #define B_PANELIZE    B_USER+3
  93.  
  94. #define B_TREE     B_USER+1
  95.  
  96. /* A list of directories to be ignores, separated with ':' */
  97. char *find_ignore_dirs = 0;
  98.  
  99. static Dlg_head *find_dlg;    /* The dialog */
  100. static WInput *in_start;    /* Start path */
  101. static WInput *in_name;        /* Pattern to search */
  102. static WListbox *find_list;    /* Listbox with the file list */
  103. static int running = 0;        /* nice flag */
  104. static WButton *stop_button;    /* pointer to the stop button */
  105. static WLabel *status_label;    /* Finished, Searching etc. */
  106. static char *find_pattern;    /* Pattern to search */
  107. static int count;        /* Number of files displayed */
  108. static int matches;        /* Number of matches */
  109. static int is_start;        /* Status of the start/stop toggle button */
  110. int max_loops_in_idle = 10;
  111. static char *old_dir;
  112.  
  113. static int find_par_callback (struct Dlg_head *h, int id, int Msg)
  114. {
  115. #ifndef HAVE_X
  116.     switch (Msg){
  117.     case DLG_DRAW:
  118.     attrset (REVERSE_COLOR);
  119.     dlg_erase (h);
  120.     draw_box (h, 1, 1, FIND_Y-2, FIND_X-2);
  121.     break;
  122.     }
  123. #endif
  124.     return 0;
  125. }
  126.  
  127. static char *in_start_dir = NULL;
  128. static char *in_start_name = NULL;
  129.  
  130. static int find_parameters (char **start_dir, char **pattern)
  131. {
  132.     int return_value;
  133.     char *temp_dir;
  134.  
  135.  find_par_start:
  136.     if (!in_start_dir)
  137.     in_start_dir = strdup (".");
  138.     if (!in_start_name)
  139.     in_start_name = strdup (easy_patterns ? "*" : ".");
  140.     find_dlg = create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
  141.                find_par_callback, "[Find File]", "findfile",
  142.                DLG_CENTER);
  143.     x_set_dialog_title (find_dlg, "Find File");
  144.  
  145.     in_start = input_new (3, 14, INPUT_COLOR, 30, in_start_dir);
  146.     in_name  = input_new (5, 14, INPUT_COLOR, 30, in_start_name);
  147.  
  148. #ifndef HAVE_XVIEW
  149.     add_widget (find_dlg, in_start);
  150. #endif
  151.     tk_new_frame (find_dlg, "b.");
  152.     add_widgetl (find_dlg, button_new (7, 36, B_CANCEL,"[ Cancel ]",'c',2,0,0),
  153.         XV_WLAY_RIGHTOF);
  154.     
  155. #if HAVE_AVOID_DIRS
  156.     add_widgetl (find_dlg, button_new (7, 22, B_USER, "[ Avoid... ]",
  157.                       'a', 2,
  158.                       avoid_box, 0),
  159.              XV_WLAY_RIGHTOF);
  160. #endif
  161.  
  162.     add_widgetl (find_dlg, button_new (7, 12, B_TREE, "[ Tree ]", 't', 2,0,0),
  163.         XV_WLAY_RIGHTOF);
  164.     add_widgetl (find_dlg, button_new (7, 4, B_ENTER,"[ Ok ]",'o', 2, 0, 0),
  165.         XV_WLAY_CENTERROW);
  166.     tk_end_frame ();
  167.     add_widgetl (find_dlg, in_name, XV_WLAY_RIGHTOF);
  168.  
  169.     
  170.     add_widgetl (find_dlg, label_new (5, 3, "Filename:"), XV_WLAY_NEXTROW);
  171.  
  172. #ifdef HAVE_XVIEW
  173.     add_widgetl (find_dlg, in_start, XV_WLAY_RIGHTOF);
  174. #endif    
  175.     add_widget (find_dlg, label_new (3, 3, "Start at:"));
  176.  
  177.     run_dlg (find_dlg);
  178.     if (find_dlg->ret_value == B_CANCEL)
  179.     return_value = 0;
  180.     else if (find_dlg->ret_value == B_TREE){
  181.     temp_dir = strdup (in_start->buffer);
  182.     destroy_dlg (find_dlg);
  183.     free (in_start_dir);
  184.     if (strcmp (temp_dir, ".") == 0){
  185.         free (temp_dir);
  186.         temp_dir = strdup (cpanel->cwd);
  187.     }
  188.     in_start_dir = tree (temp_dir);
  189.     if (in_start_dir)
  190.         free (temp_dir);
  191.     else
  192.         in_start_dir = temp_dir;
  193.     /* Warning: Dreadful goto */
  194.     goto find_par_start;
  195.     } else {
  196.     return_value = 1;
  197.     *start_dir = strdup (in_start->buffer);
  198.     *pattern   = strdup (in_name->buffer);
  199.     free (in_start_dir);
  200.     in_start_dir = strdup (*start_dir);
  201.     free (in_start_name);
  202.     in_start_name = strdup (*pattern);
  203.     }
  204.  
  205.     destroy_dlg (find_dlg);
  206.              
  207.     return return_value;
  208. }
  209.  
  210. typedef struct dir_stack {
  211.     char *name;
  212.     struct dir_stack *prev;
  213. } dir_stack ;
  214.  
  215. dir_stack *dir_stack_base = 0;
  216.  
  217. static void push_directory (char *dir)
  218. {
  219.     dir_stack *new;
  220.  
  221.     new = xmalloc (sizeof (dir_stack), "find: push_directory");
  222.     new->name = strdup (dir);
  223.     new->prev = dir_stack_base;
  224.     dir_stack_base = new;
  225. }
  226.  
  227. static char *pop_directory (void)
  228. {
  229.     char *name; 
  230.     dir_stack *next;
  231.  
  232.     if (dir_stack_base){
  233.     name = dir_stack_base->name;
  234.     next = dir_stack_base->prev;
  235.     free (dir_stack_base);
  236.     dir_stack_base = next;
  237.     return name;
  238.     } else
  239.     return 0;
  240. }
  241.  
  242. static void insert_file (char *dir, char *file)
  243. {
  244.     char *tmp_name;
  245.     static char *dirname;
  246.     int i;
  247.  
  248.     if (dir [0] == '/' && dir [1] == '/')
  249.     dir++;
  250.     i = strlen (dir);
  251.     if (i){
  252.     if (dir [i - 1] != '/'){
  253.         dir [i] = '/';
  254.         dir [i + 1] = 0;
  255.     }
  256.     }
  257.  
  258.     if (old_dir){
  259.     if (strcmp (old_dir, dir)){
  260.         free (old_dir);
  261.         old_dir = strdup (dir);
  262.         dirname = listbox_add_item (find_list, 0, 0, dir, 0);
  263.     }
  264.     } else {
  265.     old_dir = strdup (dir);
  266.     dirname = listbox_add_item (find_list, 0, 0, dir, 0);
  267.     }
  268.     
  269.     tmp_name = copy_strings ("    ", file, 0);
  270.     listbox_add_item (find_list, 0, 0, tmp_name, dirname);
  271.     free (tmp_name);
  272. }
  273.  
  274. static char *rotating_dash = "|/-\\";
  275.  
  276. static void do_search (struct Dlg_head *h)
  277. {
  278.     static struct dirent *dp   = 0;
  279.     static DIR  *dirp = 0;
  280.     static char directory [MC_MAXPATHLEN+2];
  281.     struct stat tmp_stat;
  282.     static int pos;
  283.     static int subdirs_left = 0;
  284.     char *tmp_name;        /* For bulding file names */
  285.     int p;
  286.  
  287.  do_search_begin:
  288.     while (!dp){
  289.     
  290.     if (dirp){
  291.         mc_closedir (dirp);
  292.         dirp = 0;
  293.     }
  294.     
  295.     while (!dirp){
  296.         char *tmp;
  297.  
  298. #ifndef HAVE_X        
  299.         attrset (REVERSE_COLOR);
  300. #endif
  301.         while (1) {
  302.         tmp = pop_directory ();
  303.         if (!tmp){
  304.             running = 0;
  305.             label_set_text (status_label, "Finished");
  306.             set_idle_proc (h, 0);
  307.             return;
  308.         }
  309.         if (find_ignore_dirs){
  310.             char *temp_dir = copy_strings (":", tmp, ":", 0);
  311.             if (strstr (find_ignore_dirs, temp_dir))
  312.             free (tmp);
  313.             else
  314.             break;
  315.         } else
  316.             break;
  317.         } 
  318.         
  319.         strcpy (directory, tmp);
  320.         free (tmp);
  321.  
  322.         if (verbose){
  323.             char buffer [50];
  324.             
  325.             sprintf (buffer, "Searching %s", name_trunc (directory, 
  326. #ifndef HAVE_X
  327.             FIND2_X-20
  328. #else            
  329.             35
  330. #endif
  331.             ));
  332.             label_set_text (status_label, buffer);
  333.         }
  334.         dirp = mc_opendir (directory);
  335.         mc_stat (directory, &tmp_stat);
  336.         subdirs_left = tmp_stat.st_nlink - 2;
  337.         /* Commented out as unnecessary
  338.         if (subdirs_left < 0)
  339.             subdirs_left = MAXINT;
  340.         */
  341.     }
  342.     dp = mc_readdir (dirp);
  343.     }
  344.  
  345.     if (strcmp (dp->d_name, ".") == 0 ||
  346.     strcmp (dp->d_name, "..") == 0){
  347.     dp = mc_readdir (dirp);
  348. #ifdef HAVE_XVIEW
  349.     xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
  350. #endif        
  351.     return;
  352.     }
  353.     
  354.     tmp_name = get_full_name (directory, dp->d_name);
  355.  
  356.     if (subdirs_left){
  357.     mc_lstat (tmp_name, &tmp_stat);
  358.     if (S_ISDIR (tmp_stat.st_mode)){
  359.         push_directory (tmp_name);
  360.         subdirs_left--;
  361.     }
  362.     }
  363.     
  364.     if (regexp_match (find_pattern, dp->d_name, match_file)){
  365.     insert_file (directory, dp->d_name);
  366.     matches++;
  367.  
  368.     p = matches & 7;
  369.  
  370.     if (!p)
  371.         listbox_select_last (find_list, 1);
  372.     else
  373.         listbox_select_last (find_list, 0);
  374.  
  375. #ifndef HAVE_X
  376.     /* Updates the current listing */
  377.     send_message (h, &find_list->widget, WIDGET_DRAW, 0);
  378.     if (p == 7)
  379.         refresh ();
  380. #endif        
  381.     }
  382.     
  383.     free (tmp_name);
  384.     dp = mc_readdir (dirp);
  385.  
  386.     /* Displays the nice dot */
  387.     count++;
  388.     if (!(count & 31)){
  389.     if (verbose){
  390. #ifndef HAVE_X
  391.         pos = (++pos) % 4;
  392.         attrset (NORMALC);
  393.         dlg_move (h, FIND2_Y-6, FIND2_X - 4);
  394.         addch (rotating_dash [pos]);
  395.         refresh ();
  396.     }
  397.     } else
  398.     goto do_search_begin;
  399. #else
  400.         }
  401.     }
  402. #ifdef HAVE_XVIEW
  403.     xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
  404. #endif        
  405. #endif
  406.  
  407. }
  408.  
  409. static int find_callback (struct Dlg_head *h, int id, int Msg)
  410. {
  411.     switch (Msg){
  412. #ifndef HAVE_X    
  413.     case DLG_DRAW:
  414.     attrset (REVERSE_COLOR);
  415.     dlg_erase (h);
  416.     draw_box (h, 1, 1, FIND2_Y-2, FIND2_X-2);
  417.     attrset (COLOR_HOT_NORMAL);
  418.     dlg_move (h, 1, 2);
  419.     addstr (" Find file ");
  420.     break;
  421. #endif
  422.  
  423.     case DLG_KEY:
  424.     if (id == KEY_F(3) || id == KEY_F(13)){
  425.         int unparsed_view = (id == KEY_F(13));
  426.         WLEntry *entry = find_list->current;
  427.         char *dir, *name;
  428.  
  429.         dir = entry->data;
  430.         
  431.         if (!entry->text || !dir)
  432.         return MSG_NOT_HANDLED;
  433.  
  434.         if (dir [0] == '.' && dir [1] == 0)
  435.         name = strdup (entry->text + 4);
  436.         else if (dir [0] == '.' && dir [1] == '/')
  437.         name = get_full_name (dir+2, entry->text + 4);
  438.         else
  439.         name = get_full_name (dir, entry->text+4);
  440.  
  441.         view_file (name, unparsed_view, use_internal_view);
  442.         free (name);
  443.         return MSG_HANDLED;
  444.     }
  445.     return MSG_NOT_HANDLED;
  446.     
  447.     case DLG_IDLE:
  448.     do_search (h);
  449.     break;
  450.     }
  451.     return 0;
  452. }
  453.  
  454. #define BUTTON_NEW(i,msg,str) \
  455.    button_new (FIND2_Y-4, 3+i*12, msg, str, str [2], 2, 0, 0)
  456.  
  457. #define BUTTON_NEW_CBACK(i,msg,str,a,b) \
  458.    button_new (FIND2_Y-4, 3+i*12, msg, str, str [2], 2, a, b)
  459.  
  460. /* Handles the Stop/Start button in the find window */
  461. static int start_stop (int button, void *extra)
  462. {
  463.     char *button_labels [2] = { "[ Stop ] ", "[ Start ]" };
  464.     
  465.     running = is_start;
  466.     set_idle_proc (find_dlg, running);
  467.     is_start = !is_start;
  468.  
  469.     label_set_text (status_label, is_start ? "Stopped" : "Searching");
  470.     button_set_text (stop_button, button_labels [is_start]);
  471.     
  472.     return 0;
  473. }
  474.  
  475. static void init_find_vars (void)
  476. {
  477.     char *dir;
  478.     
  479.     if (old_dir){
  480.     free (old_dir);
  481.     old_dir = 0;
  482.     }
  483.     count = 0;
  484.     matches = 0;
  485.  
  486.     /* Remove all the items in the stack */
  487.     while ((dir = pop_directory ()) != NULL)
  488.     free (dir);
  489. }
  490.  
  491. static int find_file (char *start_dir, char *pattern,
  492.               char **dirname,  char **filename)
  493. {
  494.     int return_value = 0;
  495.     char *dir;
  496.     char *dir_tmp, *file_tmp;
  497.     
  498.     find_dlg = create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors,
  499.                find_callback, "[Find File]", "mfind", DLG_CENTER);
  500.     
  501.     x_set_dialog_title (find_dlg, "Find file");
  502.  
  503.     find_list = listbox_new (2, 2, FIND2_X-4, FIND2_Y-9, listbox_finish, 0);
  504.  
  505. #ifndef HAVE_X
  506.     add_widget (find_dlg, find_list);
  507. #endif
  508.  
  509.     tk_new_frame (find_dlg, "b.");
  510.     add_widgetl (find_dlg,
  511.         button_new (FIND2_Y-3, 3, B_PANELIZE, "[ Panelize ]", 'p', 2, 0, 0),
  512.         XV_WLAY_CENTERROW);
  513.     add_widgetl (find_dlg, BUTTON_NEW (3, B_CANCEL, "[ Quit ]"),
  514.         XV_WLAY_RIGHTOF);
  515.     stop_button = BUTTON_NEW_CBACK (2, B_STOP,   "[ Stop  ]", start_stop,
  516.                     find_dlg);
  517.     add_widgetl (find_dlg, stop_button,
  518.         XV_WLAY_RIGHTOF);
  519.     add_widgetl (find_dlg, BUTTON_NEW (1, B_AGAIN,  "[ Again ]"),
  520.         XV_WLAY_RIGHTOF);
  521.     add_widgetl (find_dlg, BUTTON_NEW (0, B_ENTER,  "[ Chdir ]"), 
  522.         XV_WLAY_CENTERROW);
  523.     tk_end_frame ();
  524.  
  525.     status_label = label_new (FIND2_Y-6, 4, "Searching");
  526.     add_widgetl (find_dlg, status_label, XV_WLAY_BELOWOF);
  527. #ifdef HAVE_X
  528.     add_widgetl (find_dlg, find_list, XV_WLAY_EXTENDWIDTH);
  529. #endif
  530.  
  531.     /* Need to cleanup this */
  532.     find_pattern = pattern;
  533.  
  534.     set_idle_proc (find_dlg, 1);
  535.     init_find_vars ();
  536.     push_directory (start_dir);
  537.  
  538. #ifdef HAVE_XVIEW
  539.     xv_post_proc (find_dlg, (void (*)(void *))do_search, (void *)find_dlg);
  540. #endif    
  541.     run_dlg (find_dlg);
  542.  
  543.     return_value = find_dlg->ret_value;
  544.  
  545.     /* Remove all the items in the stack */
  546.     while ((dir = pop_directory ()) != NULL)
  547.     free (dir);
  548.     
  549.     listbox_get_current (find_list, &file_tmp, &dir_tmp);
  550.  
  551.     if (dir_tmp)
  552.     *dirname  = strdup (dir_tmp);
  553.     if (file_tmp)
  554.     *filename = strdup (file_tmp);
  555.     if (return_value == B_PANELIZE && *dirname && *filename){
  556.     struct dirent dp;
  557.     int status, link_to_dir, stalled_link;
  558.     int next_free = 0;
  559.     int i;
  560.     struct stat buf;
  561.     WLEntry *entry = find_list->list;
  562.     dir_list *list = &cpanel->dir;
  563.     char *dir, *name;
  564.  
  565.     clean_dir (list, cpanel->count);
  566.     for (i = 0; entry && i < find_list->count; entry = entry->next, i++){
  567.         if (!entry->text || !entry->data)
  568.         continue;
  569.         dir = entry->data;
  570.         if (dir [0] == '.' && dir [1] == 0)
  571.         name = strdup (entry->text + 4);
  572.         else if (dir [0] == '.' && dir [1] == '/')
  573.         name = get_full_name (dir + 2, entry->text + 4);
  574.         else
  575.         name = get_full_name (dir, entry->text + 4);
  576.         strcpy (dp.d_name, name);
  577.         free (name);
  578. #if !defined(HAVE_DIRENT_H) && !defined(_POSIX_VERSION)
  579.         NLENGTH (&dp) = strlen (dp.d_name);
  580. #endif
  581.         status = handle_dirent (list, NULL, &dp, &buf, next_free, &link_to_dir,
  582.             &stalled_link);
  583.         if (status == 0)
  584.         continue;
  585.         if (status == -1)
  586.         break;
  587.         list->list [next_free].fnamelen = strlen (dp.d_name);
  588.         list->list [next_free].fname = strdup (dp.d_name);
  589.         list->list [next_free].cache = NULL;
  590.         file_mark (cpanel, next_free, 0);
  591.         list->list [next_free].f.link_to_dir = link_to_dir;
  592.         list->list [next_free].f.stalled_link = stalled_link;
  593.         list->list [next_free].buf = buf;
  594.         next_free++;
  595.            if (!(next_free & 15))
  596.            rotate_dash ();
  597.     }
  598.     if (next_free){
  599.         cpanel->count = next_free;
  600.         cpanel->is_panelized = 1;
  601.         if (start_dir [0] == '/'){
  602.         strcpy (cpanel->cwd, "/");
  603.         chdir ("/");
  604.         }
  605.     }
  606.     }
  607.  
  608.     destroy_dlg (find_dlg);
  609.     if (old_dir){
  610.     free (old_dir);
  611.     old_dir = 0;
  612.     }
  613.     return return_value;
  614. }
  615.  
  616. void do_find (void)
  617. {
  618.     char *start_dir, *pattern;
  619.     char *filename, *dirname;
  620.     int  v, dir_and_file_set;
  621.     int done = 0;
  622.     
  623.     while (!done){
  624.     if (!find_parameters (&start_dir, &pattern))
  625.         break;
  626.  
  627.     dirname = filename = NULL;
  628.     v = find_file (start_dir, pattern, &dirname, &filename);
  629.     free (start_dir);
  630.     free (pattern);
  631.  
  632.     if (v == B_ENTER){
  633.         if (dirname || filename){
  634.         if (dirname){
  635.             do_cd (dirname);
  636.             if (filename)
  637.             try_to_select (current_panel, filename + 4);
  638.         } else if (filename)
  639.             do_cd (filename);
  640.         paint_panel (current_panel);
  641.         select_item (cpanel);
  642.         }
  643.         break;
  644.     }
  645.     dir_and_file_set = dirname && filename;
  646.     if (dirname)  free (dirname);
  647.     if (filename) free (filename);
  648.     if (v == B_CANCEL)
  649.         break;
  650.     if (v == B_PANELIZE){
  651.         if (dir_and_file_set){
  652.             try_to_select (cpanel, NULL);
  653.             paint_panel (cpanel);
  654.         }
  655.         break;
  656.     }
  657.     }
  658. }
  659.  
  660.